import numpy
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import TomekLinks

from tools.plot_model import plot_singleModel
import warnings
warnings.filterwarnings("ignore")


def stacking(filePath):
    accuracy_list, precision_list, recall_list, f1_list = [], [], [], []
    data = pd.read_csv(filePath)
    # print(data)

    column_names = ['loc', 'v(g)', 'ev(g)', 'iv(g)', 'n', 'v', 'l', 'd', 'i', 'e', 'b', 't', 'lOCode', 'lOComment',
                    'lOBlank', 'lOCodeAndComment', 'uniq_Op', 'uniq_Opnd', 'total_Op', 'total_Opnd', 'branchCount']
    # print(column_names)
    kc2_df = pd.DataFrame(data=data, columns=column_names)
    # print(kc2_df)

    y = pd.DataFrame(data=data, columns=['defects'])
    # print(y)


    # 创建 SMOTE 对象
    smote = SMOTE(sampling_strategy=1.0, random_state=42)  # 1.0 表示将类别1的数量提升到类别0的数量
    # 使用 SMOTE 进行过采样
    X_resampled, y_resampled = smote.fit_resample(kc2_df, y)

    # 使用 TomekLinks 进行欠采样
    tl = TomekLinks(sampling_strategy='auto')
    X_resampled, y_resampled = tl.fit_resample(X_resampled, y_resampled)

    # print(X_resampled)
    # print(y_resampled)

    from sklearn.ensemble import StackingClassifier
    from sklearn.ensemble import RandomForestClassifier
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.linear_model import LogisticRegression

    # 创建第一层的基本学习器
    base_learners = [
        ('rf', RandomForestClassifier(n_estimators=1000, random_state=42, max_depth=200)),
        ('dt', DecisionTreeClassifier(criterion='entropy', max_depth=10))
    ]

    # 创建第二层的元学习器
    meta_learner = LogisticRegression()

    # 创建StackingClassifier
    stacking_clf = StackingClassifier(estimators=base_learners, final_estimator=meta_learner)

    # 创建PCA实例并拟合数据
    pca = PCA(n_components=3)  # 选择要保留的主成分数量
    X_pca = pca.fit_transform(X_resampled)  # X是你的特征矩阵

    for i in range(1, 11):
        X_train, X_test, y_train, y_test = train_test_split(X_pca, y_resampled, test_size=0.3, random_state=42)
        # print(X_train)
        # print(y_train)

        # 训练Stacking模型
        stacking_clf.fit(X_train, y_train)

        # 预测
        y_pred = stacking_clf.predict(X_test)

        accuracy = accuracy_score(y_test, y_pred)
        precision = precision_score(y_test, y_pred)
        recall = recall_score(y_test, y_pred)
        f1 = f1_score(y_test, y_pred)

        # 打印模型性能指标
        print("第", i, "次:")
        print("Accuracy:", accuracy)
        print("Precision:", precision)
        print("Recall:", recall)
        print("F1 Score:", f1)

    # from sklearn.metrics import classification_report
    # report = classification_report(y_test, y_pred)
    # print(report)
        accuracy_list.append(accuracy)
        precision_list.append(precision)
        recall_list.append(recall)
        f1_list.append(f1)

    return accuracy_list, precision_list, recall_list, f1_list


if __name__ == "__main__":
    filePath = "../data/KC2.csv"
    accuracy_list, precision_list, recall_list, f1_list = stacking(filePath)
    plot_singleModel("KNN", accuracy_list, precision_list, recall_list, f1_list)